/**
 * 
 */
package research.sbookmarking.process;

import java.util.*;
import org.afox.util.*;
import research.sbookmarking.*;

import org.connotea.*;

/**
 * This class controller for processing the data retrieved from Connotea.org
 * <p> 
 * @author <A HREF="mailto:aatleung@gmail.com">Albert Leung</a>
 * @version 1.0
 */
public class ProcessController {

	private static ProcessController anInstance = null;
	
	/**
	 * The only way to instantiate this class is through 
	 * {@link #getInstance() getInstance}
	 */
	private ProcessController() {
	}

	private void increment (HashMap freq, String result) {
		Long value = null;
		
		value=(Long)freq.remove(result);
		if (value==null){
			value = new Long(0);
		}

		long val = value.longValue();
		freq.put(result,new Long(++val));
	}
	
	private void increment (HashMap freq, List results){
		Iterator list = results.iterator();
		
		while (list.hasNext()) {
			increment (freq, convertToString(list.next()));
		}
	}
	
	private void increment (HashMap freq, org.restlet.data.Reference result){
		increment (freq,result.toString());
	}
	
	private String convertToString (Object item){
		String obj = null;
		
		if (item.getClass().getName().equals("org.connotea.Tag")){
			obj = ((Tag)item).getValue();
		}
		else if (item.getClass().getName().equals("org.connotea.Bookmark")){
			obj = ((Bookmark)item).getLink().toString();
		}
		else if (item.getClass().getName().equals("org.connotea.Post")){
			obj = ((Post)item).getCreator();
		}
		else {
			obj = item.toString();
		}
		
		return obj;
	}
	
	private void checkDuplicates(List list, Object item){
		if (list.contains(item)== false) {
			list.add(convertToString(item));
		}
	}
	
	private void addItem (List list, Object values){
		try {
			Iterator items = ((List)values).iterator();
			while (items.hasNext()) {
				checkDuplicates(list,convertToString(items.next()));
			}
		}
		catch (java.lang.ClassCastException x) {
			checkDuplicates(list,values);
		}
	}
	
	private void addObject (HashMap temp, String key, Object value) {
		List list = new ArrayList();
		
		list=(List)temp.remove(key);
		if (list==null){
			list = new ArrayList();
		}
		
		addItem (list,value);
		temp.put(key, list);
	}
	
	private String getKey(Post aPost, String command){
		if (command.equals("getBookmark")){
			return aPost.getBookmark().getLink().toString();
		}
		else if (command.equals("getCreator")) {
			return aPost.getCreator();
		}
		return null;
	}
	
	private void calcFreq (DataContainer data){
		//number of times an URL has been bookmarked
		HashMap bookmarkFreq = data.getFreqBookmarks();
		
		//number of times a user posted
		HashMap userFreq = data.getFreqUsers();

		HashMap tagFreq = data.getFreqTags();

		//the list of users for each URL
		HashMap urlUser = data.getUrlUser();
		
		Iterator results = data.getQueryResults().iterator();
		
		while (results.hasNext()){
			Post aPost= (Post)results.next();
			Bookmark query = aPost.getBookmark();
			
/*
			if (bookmarkFreq.get(query)==null){
				bookmarkFreq.put(query.getLink(), new Long(query.getPostCount()));
				urlUser.put(query.getLink(), query.getPostedBy());
			}
*/
			increment (bookmarkFreq,query.getLink());
			increment (userFreq,aPost.getCreator());
			increment (tagFreq,aPost.getSubjects());
			addObject(urlUser,query.getLink().toString(),aPost.getCreator());
		}
		
		data.setFreqBookmarks(bookmarkFreq);
		data.setFreqUsers(userFreq);
		data.setFreqTags(tagFreq);
		data.setUrlUser(urlUser);
	}
	
	private Object calcTags (String command, String choice, DataContainer data, HashMap keys){
		Iterator results = data.getQueryResults().iterator();
		
		while (results.hasNext()){
			Post aPost = (Post)results.next();
			
			String key = getKey(aPost, command);
			HashMap tagsFreq = (HashMap)keys.get(key);
			if (tagsFreq == null) {
				tagsFreq = new HashMap();
			}
			else {
				List subjects = aPost.getSubjects();
				if (choice.equals("freq")) {
						increment (tagsFreq, subjects);
				}
				else if (choice.equals("subject")) {
					addObject(tagsFreq, aPost.getCreator() , subjects); 
				}
			}
			keys.put(key, tagsFreq);
		}
		
		return keys;
	}
	
	/**
	 * Ensures that there is only one ProcessController instance. If an
	 * instance already exists it return the address of that instance
	 * otherwise it will instantiate an instance and save it.
	 * <p>
	 * @return an instance of this object.
	 */
	public static ProcessController getInstance() {
		if (anInstance==null) {
			anInstance = new ProcessController();
		}
		
		return anInstance;
	}

	public void getUsers (DataContainer dataContainer){
		Iterator data = dataContainer.getQueryResults().iterator();
		List username = new ArrayList();
		
		while (data.hasNext()){
			Post aPost = (Post)data.next();
			if (username.contains(aPost.getCreator())==false){
				username.add(aPost.getCreator());
			}
		}
		
		List param = new ArrayList();
		param.add(username);
		RMethod.invoke(dataContainer,"setUniqueUsers",param);
	}

	public void processData (DataContainer aDataContainer){
		calcFreq(aDataContainer);
		aDataContainer.setUrlTags((HashMap)calcTags("getBookmark","freq",aDataContainer,aDataContainer.getUrlTags()));
		aDataContainer.setUserTags((HashMap)calcTags("getCreator","freq",aDataContainer,aDataContainer.getUserTags()));
		aDataContainer.setUrlUserTags((HashMap)calcTags("getBookmark","subject",aDataContainer,aDataContainer.getUrlUserTags()));
		aDataContainer.setQueryResults(null);
	}
	
	public void processData (List dataContainers){
		Iterator iterator = dataContainers.iterator();
		
		while (iterator.hasNext()){
			processData((DataContainer)iterator.next());
		}
	}

	/* For Debugging purposes
	 * 
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}
	 */
}
